﻿using System;
using Framework.Task;
using System.Collections.Generic;

namespace Framework.Resource
{
    public class LoadAssetTaskAgent : ITaskAgent<LoadAssetTask>
    {
        private LoadAssetTask m_Task;
        private ResourceManager m_ResourceManager;
        private ILoadAssetHelper m_LoadAssetHelper = null;
        private List<string> m_WaitLoadingResources = null;

        public LoadAssetTask Task
        {
            get
            {
                return m_Task;
            }
        }
        public LoadAssetTaskAgent(ResourceManager resourceManager, ILoadAssetHelper loadAssetHelper)
        {
            m_ResourceManager = resourceManager;
            m_LoadAssetHelper = loadAssetHelper;
            if (m_LoadAssetHelper != null)
            {
                m_LoadAssetHelper.Init();
                m_LoadAssetHelper.LoadProgressEvent += LoadAssetUpate;
                m_LoadAssetHelper.LoadCompleteEvent += LoadAssetComplete;
                m_LoadAssetHelper.LoadErrorEvent += LoadAssetError;
            }
            m_WaitLoadingResources = new List<string>();
        }
        public void Init()
        {
            m_Task = null;
            m_WaitLoadingResources.Clear();
        }
        public void Reset()
        {
            m_Task = null;
            if(m_LoadAssetHelper != null)
                m_LoadAssetHelper.Reset();
            m_WaitLoadingResources.Clear();
        }
        public void Destroy()
        {
            m_LoadAssetHelper.LoadProgressEvent -= LoadAssetUpate;
            m_LoadAssetHelper.LoadCompleteEvent -= LoadAssetComplete;
            m_LoadAssetHelper.LoadErrorEvent -= LoadAssetError;
            if (m_LoadAssetHelper != null)
                m_LoadAssetHelper.Destroy();
            m_Task = null;
            m_ResourceManager = null;
            m_LoadAssetHelper = null;
            m_WaitLoadingResources.Clear();
            m_WaitLoadingResources = null;
        }
        public void Start(LoadAssetTask task)
        {
            if (task == null)
                return;
            m_Task = task;
            LoadAssetStart();
            if (m_ResourceManager.HasLoadAsset(m_Task.PackageName))
            {
                m_Task.Status = LoadAssetStatus.Complete;
                return;
            }
            if (m_ResourceManager.IsLoadingPackage(m_Task.PackageName))
            {
                m_Task.Status = LoadAssetStatus.WaitLoadingResource;
                return;
            }
            LoadAsset();
        }
        public void Update(float frameTime, float realTime)
        {
            if (m_Task == null || m_Task.Status == LoadAssetStatus.None) return;
            if(m_Task.Status == LoadAssetStatus.LoadingDependence)
            {
                string[] dependentNames = m_Task.DependentNames;
                for (int i = 0; i < dependentNames.Length; i++)
                {
                    string packageName = dependentNames[i];
                    if (m_ResourceManager.HasLoadAsset(packageName))
                        continue;
                    m_Task.Status = LoadAssetStatus.WaitLoadingDependence;
                    if(m_ResourceManager.IsLoadingPackage(packageName) == false && m_ResourceManager.IsWaitLoadingPackage(packageName) == false)
                    {
                        m_ResourceManager.AddWaitLoadingPackage(packageName);
                        m_ResourceManager.LoadAssetAsyc(packageName, null, null, null, null, null);
                    }
                    m_WaitLoadingResources.Add(packageName);
                }
            }
            else if(m_Task.Status == LoadAssetStatus.WaitLoadingDependence)
            {
                for (int i = m_WaitLoadingResources.Count - 1; i >= 0; i--)
                {
                    if(m_ResourceManager.HasLoadAsset(m_WaitLoadingResources[i]))
                        m_WaitLoadingResources.RemoveAt(i);
                }
                if (m_WaitLoadingResources.Count <= 0)
                    m_Task.Status = LoadAssetStatus.LoadingResource;
            }
            else if(m_Task.Status == LoadAssetStatus.LoadingResource)
            {
                if (m_ResourceManager.HasLoadAsset(m_Task.PackageName))
                {
                    m_Task.Status = LoadAssetStatus.Complete;
                    return;
                }
                if (m_ResourceManager.IsLoadingPackage(m_Task.PackageName) == false)
                {
                    m_ResourceManager.AddLoadingPackage(m_Task.PackageName);
                    m_ResourceManager.RemoveWaitLoadingPackage(m_Task.PackageName);
                    m_LoadAssetHelper.LoadAssetAsync(m_Task.PackageName);
                }
                m_Task.Status = LoadAssetStatus.WaitLoadingResource;
            }
            else if(m_Task.Status == LoadAssetStatus.WaitLoadingResource)
            {
                if (m_ResourceManager.HasLoadAsset(m_Task.PackageName))
                {
                    m_ResourceManager.RemoveLoadingPackage(m_Task.PackageName);
                    m_Task.Status = LoadAssetStatus.Complete;
                }
            }
            else if(m_Task.Status == LoadAssetStatus.Complete)
            {
                AssetPackage packageRes = m_ResourceManager.GetCache(m_Task.PackageName);
                object resObj = null;
                string[] dependentNames = m_Task.DependentNames;
                if(packageRes != null)
                {
                    for (int i = 0; i < dependentNames.Length; i++)
                    {
                        AssetPackage dependPackage = m_ResourceManager.GetCache(dependentNames[i]);
                        if (dependPackage != null)
                        {
                            dependPackage.AddReferencePackage(packageRes);
                            packageRes.AddDependentPackage(dependPackage);
                        }
                    }
                    if (string.IsNullOrEmpty(m_Task.AssetName) == false)
                    {
                        resObj = packageRes.LoadAsset(m_Task.AssetName);
                    }
                    else
                    {
                        resObj = packageRes;
                    }
                }
                if (m_Task.LoadSuccessCallback != null)
                    m_Task.LoadSuccessCallback(m_Task.PackageName, m_Task.AssetName, resObj);
                m_Task.Done = true;
            }
        }

        private void LoadAsset()
        {
            if (m_Task == null) return;
            string[] dependentNames = m_Task.DependentNames;
            if(dependentNames != null && dependentNames.Length > 0)
            {
                m_Task.Status = LoadAssetStatus.LoadingDependence;
                return;
            }
            m_Task.Status = LoadAssetStatus.LoadingResource;
        }
        private void LoadAssetStart()
        {
            if (m_Task != null && m_Task.LoadStartCallback != null)
                m_Task.LoadStartCallback(m_Task.PackageName, m_Task.AssetName);
        }
        private void LoadAssetUpate(int progress)
        {
            if (m_Task != null && m_Task.LoadUpdateCallback != null)
                m_Task.LoadUpdateCallback(m_Task.PackageName, m_Task.AssetName, progress);
        }
        private void LoadAssetComplete(object resObj)
        {
            if (m_Task == null) return;
            if (resObj != null)
            {
                object tempObj = resObj;
                AssetPackage package = m_ResourceManager.AddAssetCache(m_Task.PackageName, resObj);
                if (package != null)
                {
                    string[] dependentNames = m_Task.DependentNames;
                    for (int i = 0; i < dependentNames.Length; i++)
                    {
                        AssetPackage dependPackage = m_ResourceManager.GetCache(dependentNames[i]);
                        if (dependPackage != null)
                        {
                            dependPackage.AddReferencePackage(package);
                            package.AddDependentPackage(dependPackage);
                        }
                    }
                    if (string.IsNullOrEmpty(m_Task.AssetName) == false)
                    {
                        tempObj = package.LoadAsset(m_Task.AssetName);
                    }
                    else
                    {
                        tempObj = package;
                    }
                }
                if (m_Task.LoadSuccessCallback != null)
                    m_Task.LoadSuccessCallback(m_Task.PackageName, m_Task.AssetName, tempObj);
            }
            m_Task.Done = true;
        }
        private void LoadAssetError(string error)
        {
            if (m_Task == null) return;
            m_Task.Done = true;
            if (m_Task != null && m_Task.LoadFailureCallBack != null)
                m_Task.LoadFailureCallBack(m_Task.PackageName, m_Task.AssetName, error);
        }
    }
}

